#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include "backend.h"
#include "common.h"
#include "runtime.h"
#include "ast.h"
#include "execution.c"

/* Enumerate Table */
int enum_basic_count = 0;
int enum_combo_count = 0;
struct enum_basic *enum_basic_table = NULL;
struct enum_combo *enum_combo_table = NULL;

/* Type Table */
int type_count = 0;
struct type *type_table = NULL;

/* Global Variable Table */
int global_var_count = 0;
struct variable_declaration *global_var_table_dec = NULL;
void *globar_var_table = NULL;

/* Event Table */
int event_count = 0;
struct event *event_table = NULL;

/* Function Table */
int function_count = 0;
struct function *function_table = NULL;

/* ================ */
/* == Validation == */
/* ================ */

void validate(struct translationunit *unit)
{
	validate_enumlist(unit->e);

	global_var_count = unit->v->count;
	global_var_table_dec = validate_varlist(unit->v);

	validate_functionlist(unit->f);
}

/* == Enumerate == */

void validate_enumlist(struct e_list *el)
{
	int h, i, j, k;
	struct e_node *z;
	struct e_enumerate *y;
	struct e_elemlist *x;
	struct e_elemnode *w;
	struct i_list *v;
	struct i_node *u;

	for (z = el->first; z != NULL; z = z->next) {
		if (z->enumerate->cate == E_BASE)
			enum_basic_count ++;
		else if (z->enumerate->cate == E_COMB)
			enum_combo_count ++;
	}

	enum_basic_table = malloc(enum_basic_count * sizeof(struct enum_basic));
	T_ERROR_MALLOC(enum_basic_table);
	enum_combo_table = malloc(enum_combo_count * sizeof(struct enum_combo));
	T_ERROR_MALLOC(enum_combo_table);

	h = -1;
	for (i = 0, z = el->first; z != NULL; i++, z = z->next) {
		y = z->enumerate;

		if (y->cate != E_BASE)
			continue;

		if (validate_enum_basic_identifier(y->identifier) != -1)
			T_ERROR_IDDUPLICATE(y->identifier);

		h++;
		x = y->spec.base.elemlist;

		T_IDENTIFIER_COPY(enum_basic_table[h].identifier, y->identifier);
		enum_basic_table[h].count = x->count;
		enum_basic_table[h].elements = malloc(sizeof(struct enum_element) * x->count);
		T_ERROR_MALLOC(enum_basic_table[h].elements);

		for (j = 0, w = x->first; w != NULL; j++, w = w->next) {
			enum_basic_table[h].elements[j].enumerate = h;
			enum_basic_table[h].elements[j].index = j;
			enum_basic_table[h].elements[j].value = w->element->value;
			enum_basic_table[h].elements[j].desc = malloc(strlen(w->element->desc) + 1);
			T_ERROR_MALLOC(enum_basic_table[h].elements[j].desc);
			strcpy(enum_basic_table[h].elements[j].desc, w->element->desc);
			T_IDENTIFIER_COPY(enum_basic_table[h].elements[j].identifier, w->element->identifier);
		}
	}
	assert(h + 1 == enum_basic_count);

	h = -1;
	for (i = 0, z = el->first; z != NULL; i++, z = z->next) {
		y = z->enumerate;

		if (y->cate != E_COMB)
			continue;

		if (validate_enum_basic_identifier(y->identifier) != -1 ||
		    validate_enum_combo_identifier(y->identifier) != -1)
			T_ERROR_IDDUPLICATE(y->identifier);

		h++;
		v = y->spec.comb.identifiers;

		T_IDENTIFIER_COPY(enum_combo_table[h].identifier, y->identifier);
		enum_combo_table[h].count = v->count;
		enum_combo_table[h].components = malloc(sizeof(int) * v->count);
		T_ERROR_MALLOC(enum_combo_table[h].components);

		for (j = 0, u = v->first; u != NULL; j++, u = u->next) {
			k = validate_enum_basic_identifier(u->identifier);
			if (k == -1)
				T_ERROR_IDNOTFOUND(u->identifier);

			enum_combo_table[h].components[j] = k;
		}
	}
	assert(h + 1 == enum_combo_count);
}

int validate_enum_basic_identifier(char *id)
{
	int i;

	for (i = 0; i < enum_basic_count; i++)
		if (T_IDENTIFIER_CMP(id, enum_basic_table[i].identifier) == 0) break;

	if (i == enum_basic_count)
		return -1;
	else
		return i;
}

int validate_enum_combo_identifier(char *id)
{
	int i;

	for (i = 0; i < enum_combo_count; i++)
		if (T_IDENTIFIER_CMP(id, enum_combo_table[i].identifier) == 0) break;

	if (i == enum_combo_count)
		return -1;
	else
		return i;
}

/* == Type == */

int validate_type(struct t_type *t)
{
	int ixx = 0;
	int tt;	/* type */
	int tc; /* constant */
	int ti; /* index */
	enum type_cate ttc;

	switch (t->cate) {
	case T_INTEGER:
		for (ixx = 0; ixx < type_count; ixx++)
			if (type_table[ixx].cate == INTEGER) break;

		break;
	case T_BOOLEAN:
		for (ixx = 0; ixx < type_count; ixx++)
			if (type_table[ixx].cate == BOOLEAN) break;

		break;
	case T_ENUMERATE:
		for (ixx = 0; ixx < type_count; ixx++) {
			if (type_table[ixx].cate == ENUM_BASIC)
				if (T_IDENTIFIER_CMP(t->spec.enumerate.identifier,
						     enum_basic_table[type_table[ixx].spec.enum_basic.enumindex].identifier) == 0)
					break;
			if (type_table[ixx].cate == ENUM_COMBO)
				if (T_IDENTIFIER_CMP(t->spec.enumerate.identifier,
						     enum_combo_table[type_table[ixx].spec.enum_combo.enumindex].identifier) == 0)
					break;
		}

		break;
	case T_ARRAY_INT:
		tt = validate_type(t->spec.array_int.elemtype);
		tc = 0; /* TODO Calculate t->spec.array_int.size */

		for (ixx = 0; ixx < type_count; ixx++) {
			if (type_table[ixx].cate == ARRAY_INT &&
			    type_table[ixx].spec.array_int.size == tc &&
			    type_table[ixx].spec.array_int.elemtype == tt)
				break;
		}

		break;
	case T_ARRAY_ENUM:
		tt = validate_type(t->spec.array_enum.elemtype);

		ttc = ARRAY_ENUM_BASIC;
		ti = validate_enum_basic_identifier(t->spec.array_enum.enumerate);
		if (ti == -1) {
			ttc = ARRAY_ENUM_COMBO;
			ti = validate_enum_combo_identifier(t->spec.array_enum.enumerate);
		}
		if (ti == -1)
			T_ERROR_IDNOTFOUND(t->spec.array_enum.enumerate);

		if (ttc == ARRAY_ENUM_BASIC)
			for (ixx = 0; ixx < type_count; ixx++)
				if (type_table[ixx].cate == ttc &&
				    type_table[ixx].spec.array_enum_basic.enumindex == ti &&
				    type_table[ixx].spec.array_enum_basic.elemtype == tt)
					break;
		else
			for (ixx = 0; ixx < type_count; ixx++)
				if (type_table[ixx].cate == ttc &&
				    type_table[ixx].spec.array_enum_combo.enumindex == ti &&
				    type_table[ixx].spec.array_enum_combo.elemtype == tt)
					break;

		break;
	case T_CONTAINER:
		tt = validate_type(t->spec.container.elemtype);

		for (ixx = 0; ixx < type_count; ixx++) {
			if (type_table[ixx].cate == CONTAINER &&
			    type_table[ixx].spec.container.elemtype == tt)
				break;
		}

		break;
	default:
		assert(false);
		break;
	}

	if (ixx == type_count) {
		type_count++;
		type_table = realloc(type_table, sizeof(struct type) * (type_count));
		T_ERROR_MALLOC(type_table);

		/* TODO */
	}

	return ixx;
}

bool validate_type_compatible(int ti1, int ti2)
{
	/* Since we have indexed all types incorporated into a table, we can simply compare the indice */
	return ti1 == ti2;
}

/* == Variable Declaration == */

struct variable_declaration *validate_varlist(struct v_list *vl)
{
	int i;
	struct variable_declaration *vt;
	struct v_node *z;

	vt = malloc(sizeof(struct variable_declaration) * vl->count);
	T_ERROR_MALLOC(vt);

	for (i = 0, z = vl->first; z != NULL; i++, z = z->next) {
		T_IDENTIFIER_COPY(vt[i].identifier, z->variable->identifier);
		vt[i].type = validate_type(z->variable->type);
	}

	return vt;
}

/* == Function == */

void validate_functionlist(struct f_list *fl)
{
	int h, i;
	struct f_node *z;
	struct f_function *y;

	for (z = fl->first; z != NULL; z = z->next) {
		if (z->function->cate == F_EVENT)
			event_count++;
		else if (z->function->cate == F_FUNCTION)
			function_count++;
	}

	event_table = malloc(event_count * sizeof(struct event));
	T_ERROR_MALLOC(event_table);
	function_table = malloc(function_count * sizeof(struct function));
	T_ERROR_MALLOC(function_table);

	h = -1;
	for (i = 0, z = fl->first; z != NULL; i++, z = z->next) {
		y = z->function;

		if (y->cate != F_EVENT)
			continue;

		if (validate_event_identifier(y->identifier) != -1)
			T_ERROR_IDDUPLICATE(y->identifier);

		h++;

		T_IDENTIFIER_COPY(event_table[h].identifier, y->identifier);

		event_table[h].local_count = y->variables->count;
		event_table[h].local_table = validate_varlist(y->variables);
	}
	assert(h + 1 == event_count);

	h = -1;
	for (i = 0, z = fl->first; z != NULL; i++, z = z->next) {
		y = z->function;

		if (y->cate != F_FUNCTION)
			continue;

		if (validate_function_identifier(y->identifier) != -1)
			T_ERROR_IDDUPLICATE(y->identifier);

		h++;

		T_IDENTIFIER_COPY(function_table[h].identifier, y->identifier);
		function_table[h].type = validate_type(y->spec.function.returntype);

		function_table[h].argument_count = y->spec.function.arguments->count;
		function_table[h].argument_table = validate_varlist(y->spec.function.arguments);

		function_table[h].local_count = y->variables->count;
		function_table[h].local_table = validate_varlist(y->variables);
	}
	assert(h + 1 == function_count);

	h = -1;
	for (i = 0, z = fl->first; z != NULL; i++, z = z->next) {
		y = z->function;

		if (y->cate != F_EVENT)
			continue;

		h++;

		assert(T_IDENTIFIER_CMP(event_table[h].identifier, y->identifier) == 0);

		event_table[h].statement_count = y->statements->count;
		event_table[h].statement_table = validate_statementlist(y->statements, h, CONTEXT_NORMAL);
	}
	assert(h + 1 == event_count);

	h = -1;
	for (i = 0, z = fl->first; z != NULL; i++, z = z->next) {
		y = z->function;

		if (y->cate != F_FUNCTION)
			continue;

		h++;

		assert(T_IDENTIFIER_CMP(function_table[h].identifier, y->identifier) == 0);

		function_table[h].statement_count = y->statements->count;
		function_table[h].statement_table = validate_statementlist(y->statements, h, CONTEXT_FUNCTION);
	}
	assert(h + 1 == function_count);
}

int validate_event_identifier(char *id)
{
	int i;

	for (i = 0; i < event_count; i++)
		if (T_IDENTIFIER_CMP(id, event_table[i].identifier) == 0) break;

	if (i == event_count)
		return -1;
	else
		return i;
}

int validate_function_identifier(char *id)
{
	int i;

	for (i = 0; i < function_count; i++)
		if (T_IDENTIFIER_CMP(id, function_table[i].identifier) == 0) break;

	if (i == function_count)
		return -1;
	else
		return i;
}


/* == Statement == */

struct statement *validate_statementlist(struct s_list *sl, int feindex, int context)
{
	int i;
	struct statement *st;
	struct s_node *z;

	st = malloc(sizeof(struct statement) * sl->count);
	T_ERROR_MALLOC(st);

	for (i = 0, z = sl->first; z != NULL; i++, z = z->next) {
		validate_statement(&st[i], z->statement, feindex, context);
	}

	return st;
}

void validate_statement(struct statement *statement, struct s_statement *s, int feindex, int context)
{
	switch (s->cate) {
	case S_EXPRESSION:
		statement->cate = EXPRESSION;

		statement->spec.s_expression.expression = validate_expression(s->spec.expression.expression, feindex, context);
		break;
	case S_IF:
		statement->cate = IF;

		statement->spec.s_if.condition = validate_expression(s->spec.s_if.condition, feindex, context | CONTEXT_BOOLEAN);

		statement->spec.s_if.statement_count = s->spec.s_if.statements->count;
		statement->spec.s_if.statement_table = validate_statementlist(s->spec.s_if.statements, feindex, context);
		break;
	case S_IF_ELSE:
		statement->cate = IF_ELSE;

		statement->spec.s_if_else.condition = validate_expression(s->spec.s_if_else.condition, feindex, context | CONTEXT_BOOLEAN);

		statement->spec.s_if_else.truestatement_count = s->spec.s_if_else.truestatements->count;
		statement->spec.s_if_else.truestatement_table = validate_statementlist(s->spec.s_if_else.truestatements, feindex, context);

		statement->spec.s_if_else.falsestatement_count = s->spec.s_if_else.falsestatements->count;
		statement->spec.s_if_else.falsestatement_table = validate_statementlist(s->spec.s_if_else.falsestatements, feindex, context);
		break;
	case S_WHILE:
		statement->cate = WHILE;

		statement->spec.s_while.condition = validate_expression(s->spec.s_while.condition, feindex, context | CONTEXT_BOOLEAN);

		statement->spec.s_while.statement_count = s->spec.s_while.statements->count;
		statement->spec.s_while.statement_table = validate_statementlist(s->spec.s_while.statements, feindex, context | CONTEXT_LOOP);
		break;
	case S_DO_WHILE:
		statement->cate = DO_WHILE;

		statement->spec.s_do_while.condition = validate_expression(s->spec.s_do_while.condition, feindex, context | CONTEXT_BOOLEAN);

		statement->spec.s_do_while.statement_count = s->spec.s_do_while.statements->count;
		statement->spec.s_do_while.statement_table = validate_statementlist(s->spec.s_do_while.statements, feindex, context | CONTEXT_LOOP);
		break;
	case S_FOR:
		statement->cate = FOR;

		statement->spec.s_for.initialization = validate_expression(s->spec.s_for.initialization, feindex, context);
		statement->spec.s_for.condition = validate_expression(s->spec.s_for.condition, feindex, context | CONTEXT_BOOLEAN);
		statement->spec.s_for.iteration = validate_expression(s->spec.s_for.condition, feindex, context);

		statement->spec.s_for.statement_count = s->spec.s_for.statements->count;
		statement->spec.s_for.statement_table = validate_statementlist(s->spec.s_for.statements, feindex, context | CONTEXT_LOOP);
		break;
	case S_BREAK:
		if ((context & CONTEXT_LOOP) != CONTEXT_LOOP)
			T_ERROR_NOTINLOOP();

		statement->cate = BREAK;
		break;
	case S_CONTINUE:
		if ((context & CONTEXT_LOOP) != CONTEXT_LOOP)
			T_ERROR_NOTINLOOP();

		statement->cate = CONTINUE;
		break;
	case S_RETURN:
		statement->cate = RETURN;

		if (s->spec.s_return.value == NULL)
			statement->spec.s_return.expression = NULL;
		else
			statement->spec.s_return.expression = validate_expression(s->spec.s_return.value, feindex, context);

		if ((context & CONTEXT_FUNCTION) == CONTEXT_FUNCTION) {
			if (s->spec.s_return.value == NULL || !validate_type_compatible(function_table[feindex].type, statement->spec.s_return.expression->type))
				T_ERROR_TYPENOTCOMP();
		} else {
			if (s->spec.s_return.value != NULL)
				T_ERROR_TYPENOTCOMP();
		}

		break;
	case S_CALL:
		if ((context & CONTEXT_FUNCTION) == CONTEXT_FUNCTION)
			T_ERROR_INFUNCTION();

		statement->cate = EVENTCALL;
		statement->spec.s_eventcall.eventindex = validate_event_identifier(s->spec.s_call.eventidentifier);

		if (statement->spec.s_eventcall.eventindex == -1)
			T_ERROR_IDNOTFOUND(s->spec.s_call.eventidentifier);

		break;
	case S_TRANS:
		if ((context & CONTEXT_FUNCTION) == CONTEXT_FUNCTION)
			T_ERROR_INFUNCTION();

		statement->cate = EVENTTRANS;
		statement->spec.s_eventtrans.eventindex = validate_event_identifier(s->spec.s_trans.eventidentifier);

		if (statement->spec.s_eventtrans.eventindex == -1)
			T_ERROR_IDNOTFOUND(s->spec.s_trans.eventidentifier);

		break;
	case S_INPUT:
		statement->cate = INPUT;
		statement->spec.s_input.screen = validate_expression(s->spec.s_input.screen, feindex, context | CONTEXT_INTEGER);
		statement->spec.s_input.destination = validate_expression(s->spec.s_input.screen, feindex, context | CONTEXT_LVALUE);
		break;
	case S_OUTPUT:
		statement->cate = OUTPUT;
		statement->spec.s_output.screen = validate_expression(s->spec.s_output.screen, feindex, context | CONTEXT_INTEGER);
		statement->spec.s_output.string = malloc(strlen(s->spec.s_output.string) + 1);
		T_ERROR_MALLOC(statement->spec.s_output.string);
		strcpy(statement->spec.s_output.string, s->spec.s_output.string);
		break;
	default:
		assert(false);
	}
}

/* == Expression == */

struct expression *validate_expression(struct x_expression *x, int feindex, int context)
{
	struct expression *ex;

	ex = malloc(sizeof(struct expression));
	T_ERROR_MALLOC(ex);

	switch (x->cate) {
	case X_UNARY:
		switch (x->spec.unary.oper) {
		case X_NOT:
			ex->cate = LOGICAL_NOT;
			ex->spec.logical_not.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_BOOLEAN);
			break;
		case X_LINC:
			ex->cate = NUMERIC_LINC;
			ex->spec.numeric_linc.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_LVALUE | CONTEXT_INTEGER);
			break;
		case X_LDEC:
			ex->cate = NUMERIC_LDEC;
			ex->spec.numeric_ldec.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_LVALUE | CONTEXT_INTEGER);
			break;
		case X_LSUB:
			ex->cate = NUMERIC_LSUB;
			ex->spec.numeric_lsub.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_INTEGER);
			break;
		case X_RINC:
			ex->cate = NUMERIC_RINC;
			ex->spec.numeric_rinc.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_LVALUE | CONTEXT_INTEGER);
			break;
		case X_RDEC:
			ex->cate = NUMERIC_RDEC;
			ex->spec.numeric_rdec.expression = validate_expression(x->spec.unary.opnd, feindex, context | CONTEXT_LVALUE | CONTEXT_INTEGER);
			break;
		default:
			assert(false);
		}
		break;
	case X_BINARY:
		switch (x->spec.binary.oper) {
		case X_ASSIGN:
			ex->cate = ASSIGN;
			ex->spec.assign.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_LVALUE);
			ex->spec.assign.second = validate_expression(x->spec.binary.right, feindex, context);
			if (!validate_type_compatible(ex->spec.assign.first->type, ex->spec.assign.second->type))
				T_ERROR_TYPENOTCOMP();
			break;
		case X_OR:
			ex->cate = LOGICAL_OR;
			ex->spec.logical_or.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_BOOLEAN);
			ex->spec.logical_or.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_BOOLEAN);
			break;
		case X_AND:
			ex->cate = LOGICAL_AND;
			ex->spec.logical_and.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_BOOLEAN);
			ex->spec.logical_and.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_BOOLEAN);
			break;
		case X_EQ:
			ex->cate = COMPARE_EQ;
			ex->spec.compare_eq.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_eq.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_NE:
			ex->cate = COMPARE_NE;
			ex->spec.compare_ne.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_ne.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_LT:
			ex->cate = COMPARE_LT;
			ex->spec.compare_lt.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_lt.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_LE:
			ex->cate = COMPARE_LE;
			ex->spec.compare_le.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_le.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_GT:
			ex->cate = COMPARE_GT;
			ex->spec.compare_gt.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_gt.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_GE:
			ex->cate = COMPARE_GE;
			ex->spec.compare_ge.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.compare_ge.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_ADD:
			ex->cate = NUMERIC_ADD;
			ex->spec.numeric_add.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.numeric_add.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_SUB:
			ex->cate = NUMERIC_SUB;
			ex->spec.numeric_sub.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.numeric_sub.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_MUL:
			ex->cate = NUMERIC_MUL;
			ex->spec.numeric_mul.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.numeric_mul.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER);
			break;
		case X_DIV:
			ex->cate = NUMERIC_DIV;
			ex->spec.numeric_div.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.numeric_div.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER | CONTEXT_NONZERO);
			break;
		case X_MOD:
			ex->cate = NUMERIC_MOD;
			ex->spec.numeric_mod.first = validate_expression(x->spec.binary.left, feindex, context | CONTEXT_INTEGER);
			ex->spec.numeric_mod.second = validate_expression(x->spec.binary.right, feindex, context | CONTEXT_INTEGER | CONTEXT_NONZERO);
			break;
		default:
			assert(false);
		}
		break;
	case X_TRINARY:
		switch (x->spec.trinary.oper) {
		case X_COND:
			ex->cate = CONDITIONAL;
			ex->spec.conditional.condition = validate_expression(x->spec.trinary.first, feindex, context | CONTEXT_BOOLEAN);
			ex->spec.conditional.truevalue = validate_expression(x->spec.trinary.second, feindex, context);
			ex->spec.conditional.falsevalue = validate_expression(x->spec.trinary.third, feindex, context);
			if (!validate_type_compatible(ex->spec.conditional.truevalue->type, ex->spec.conditional.falsevalue->type))
				T_ERROR_TYPENOTCOMP();
			break;
		default:
			assert(false);
		}
		break;
	case X_IDENTIFIER:
		ex->cate = IDENTIFIER;
		/* TODO check scope accessible and type? */
		ex->spec.identifier.identifier = malloc(T_IDENTIFIER_LEN);
		T_ERROR_MALLOC(ex->spec.identifier.identifier);
		T_IDENTIFIER_COPY(ex->spec.identifier.identifier, x->spec.identifier.identifier);
		break;
	case X_INTEGER:
		ex->cate = IMMEDIATE_INT;
		ex->spec.immediate_int.value = x->spec.integer.integer;
		break;
	case X_BOOLEAN:
		ex->cate = IMMEDIATE_BOOL;
		ex->spec.immediate_bool.value = x->spec.boolean.boolean ? 1 : 0;
		break;
	case X_CALL:
		ex->cate = FUNCCALL;
		ex->spec.funccall.functionindex = validate_function_identifier(x->spec.call.function);
		/* TODO check type compatibility? */
		ex->spec.funccall.argument_count = x->spec.call.arguments->count;
		ex->spec.funccall.argument_table = validate_expressionlist(x->spec.call.arguments, feindex, context);
		break;
	case X_ARRAY:
		ex->cate = ARRAY;
		ex->spec.array.identifier = malloc(strlen(x->spec.array.array) + 1);
		T_ERROR_MALLOC(ex);
		ex->spec.array.index = validate_expression(x->spec.array.index, feindex, context);
		break;
	case X_DS:
		switch (x->spec.ds.oper) {
		case X_RANDOM:
			ex->cate = ENUM_RANDOM;
			ex->spec.enum_random.enumcate = ENUM_BASIC;
			ex->spec.enum_random.enumindex = validate_enum_basic_identifier(x->spec.ds.spec.random.type->spec.enumerate.identifier);
			if (ex->spec.enum_random.enumindex == -1) {
				ex->spec.enum_random.enumcate = ENUM_COMBO;
				ex->spec.enum_random.enumindex = validate_enum_combo_identifier(x->spec.ds.spec.random.type->spec.enumerate.identifier);
			}
			if (ex->spec.enum_random.enumindex == -1)
				T_ERROR_IDNOTFOUND(x->spec.ds.spec.random.type->spec.enumerate.identifier);
			break;
		case X_VALUE:
			ex->cate = ENUM_VALUE;
			ex->spec.enum_value.expression = validate_expression(x->spec.ds.spec.value.enumerate, feindex, context | CONTEXT_ENUM);
			break;
		case X_SIZE:
			ex->cate = CONT_SIZE;
			ex->spec.cont_size.expression = validate_expression(x->spec.ds.spec.size.container, feindex, context | CONTEXT_CONT);
			break;
		case X_FILL:
			ex->cate = CONT_FILL;
			ex->spec.cont_fill.expression = validate_expression(x->spec.ds.spec.fill.container, feindex, context | CONTEXT_CONT);
			break;
		case X_SHUFFLE:
			ex->cate = CONT_SHUFFLE;
			ex->spec.cont_shuffle.expression = validate_expression(x->spec.ds.spec.shuffle.container, feindex, context | CONTEXT_CONT);
			break;
		case X_PEEK:
			ex->cate = CONT_PEEK;
			ex->spec.cont_peek.container = validate_expression(x->spec.ds.spec.peek.container, feindex, context | CONTEXT_CONT);
			ex->spec.cont_peek.position = validate_expression_position(x->spec.ds.spec.peek.position, feindex, context);
			break;
		case X_REMOVE:
			ex->cate = CONT_REMOVE;
			ex->spec.cont_remove.container = validate_expression(x->spec.ds.spec.remove.container, feindex, context | CONTEXT_CONT);
			ex->spec.cont_remove.position = validate_expression_position(x->spec.ds.spec.remove.position, feindex, context);
			break;
		case X_INSERT:
			ex->cate = CONT_INSERT;
			/* type check TODO */
			ex->spec.cont_insert.element = validate_expression(x->spec.ds.spec.insert.element, feindex, context);
			ex->spec.cont_insert.container = validate_expression(x->spec.ds.spec.insert.container, feindex, context | CONTEXT_CONT);
			ex->spec.cont_insert.position = validate_expression_position(x->spec.ds.spec.insert.position, feindex, context);
			break;
		case X_EXTRACT:
			break;
		case X_COMBINE:
			break;
		default:
			assert(false);
		}
		break;
	default:
		assert(false);
	}

	return ex;
}

struct expression *validate_expression_position(struct p_position *p, int feindex, int context)
{
	switch (p->cate) {
	case P_TOP:
		return validate_expression_integer(0);
	case P_BOTTOM:
		return validate_expression_integer(-1);
	case P_RANDOM:
		return validate_expression_integer(-2);
	case P_EXPRESSION:
		return validate_expression(p->spec.expression.expression, feindex, context | CONTEXT_INTEGER | CONTEXT_NONNEG);
		break;
	default:
		assert(false);
	}
}

struct expression *validate_expression_integer(int v)
{
	struct expression *ex;

	ex = malloc(sizeof(struct expression));
	T_ERROR_MALLOC(ex);

	ex->cate = INTEGER;
	ex->spec.immediate_int.value = v;

	return ex;
}

struct expression *validate_expressionlist(struct x_list *xl, int feindex, int context)
{
	int i;
	struct expression *ex;
	struct x_node *z;

	ex = malloc(sizeof(struct expression) * xl->count);
	T_ERROR_MALLOC(ex);

	for (i = 0, z = xl->first; z != NULL; i++, z = z->next) {
		/* TODO */ validate_expression(z->expression, feindex, context);
	}

	return ex;
}

/* ==================== */
/* == Interpretation == */
/* ==================== */

void interpret(struct translationunit *unit)
{
//	global_vartable = allocate_varlist(unit->v);
    struct execution ret_exe = execute_event(&event_table[0],  0);
}


